﻿using System;
using System.IO;
using System.Linq;
using log4net;

namespace PortableVersion.Core.FileSystem.Services
{
    /// <summary>
    /// This servic checks out the master folder into a slave folder
    /// </summary>
    public class CheckOutService : ISynchronizationOrchestrator
    {
        private readonly IVersioningSource<FileItem> _source;
        private readonly IVersioningSource<FileItem> _target;
        private readonly IFolderBrowserService _spouceFolderService;
        private readonly IMetadataService<FileItem> _metaService;
        private readonly IConfigurationProvider _config;
        private readonly IFsoService _fso;
        private readonly ILog _log;
        private DateTime _dateTimeKey;

        public IVersioningSource<FileItem> Source
        {
            get { return _source; }
        }

        public IVersioningSource<FileItem> Target
        {
            get { return _target; }
        }

        public void Run()
        {
            _log.Info("Started running checkout service.");
            //Get the source data
            _spouceFolderService.Populate(_source);
            //Assure target folder is empty
            var di = _fso.GetDirectoryInfo(_target.Path);
            if (!di.Exists)
            {
                _log.InfoFormat("Directory '{0}' not found, so we are createing it.", _target.Path);
                _fso.CreateDirectory(_target.Path);
            }
            if (di.GetFiles().Any() || di.GetDirectories().Any())
            {
                throw new InvalidOperationException(String.Format("Target '{0}' is not empty.", _target.Path));
            }
            //Create the target versioning source and copy everything accross
            _metaService.Clear();
            _dateTimeKey = _config.GetValue<DateTime>(ConfigurationProvider.Keys.InitialDate);
            var copies = _source.Items.Select(
                i => new
                         {
                             From = i,
                             To =
                         new FileItem
                             {
                                 ModifiedDate = i.ModifiedDate,
                                 CreatedDate = GetCreatedDateKey(),
                                 Path = GetTargetPath(i.Path),
                                 Position = FilePosition.Slave,
                                 IsFolder = i.IsFolder
                             }
                         }).ToList();
            _metaService.AddItemRange(copies.Select(i => i.To));
            foreach(var i in copies)
            {
                if (i.From.IsFolder)
                {
                    _fso.CreateDirectory(i.To.Path);
                    _fso.SetDirectoryCreationTimeUtc(i.To.Path, i.To.CreatedDate);
                    _fso.SetDirectoryModifiedTeimeUtc(i.To.Path, i.To.ModifiedDate);
                }
                else
                    _fso.CopyFile(i.From, i.To, FileCopyOptions.Overwrite | FileCopyOptions.CreateFolder, null);
            }
            _metaService.Save(Path.Combine(_target.Path, _config.GetValue<string>(ConfigurationProvider.Keys.MetadataFileName)));
            _log.Info("Checkout Finished.");
        }

        private string GetTargetPath(string sourceItemPath)
        {
            var sourceBaseDir = _source.Path.ToLowerInvariant();
            var targetBaseDir = _target.Path;
            return FileSystemHelper.ReplaceCommonPath(sourceBaseDir, targetBaseDir, sourceItemPath);
        }

        private DateTime GetCreatedDateKey()
        {
            return _dateTimeKey = _dateTimeKey.AddSeconds(1);
        }

        public CheckOutService(IVersioningSource<FileItem> source, IVersioningSource<FileItem> target, IFolderBrowserService sourceSpouceFolderService, IMetadataService<FileItem> metaService,
            IConfigurationProvider config, IFsoService fso, ILog log)
        {
            _source = source;
            _target = target;
            _spouceFolderService = sourceSpouceFolderService;
            _metaService = metaService;
            _config = config;
            _fso = fso;
            _log = log;
        }
    }
}
